/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#ifndef KRONECKERWAVEFORM_H
#define KRONECKERWAVEFORM_H

#include "WaveformBase.h"

// Przestrzeń nazw
namespace RafMat
{
namespace SimEngine
{

/**
    Reprezentuje wejście typu impuls Kroneckera.

    Klasyczny impuls w regulacji dyskretnej trwa jedną próbkę i osiąga "wysokość"
    jedności. Pozwala na zbadanie odpowiedzi impulsowej obiektu dyskretnego (np.
    filtru).

    Niniejsza klasa pozwala na generowanie impulsu w dokładnie określonej chwili czasu
    oraz o określonej mocy (wartości impulsu). Można również zdefiniować poziom sygnału
    w stanie biernym. W skrajnym przypadku, dla ujemnych wartości wartości impulsu
    można uzyskać efekt "dołka" oszerokości jednej próbki.

    Wartość funkcji impulsu określana jest wzorem:

    \f{eqnarray*}{
    y(i) = L_{off} + g, \mbox{dla } i = T_i \\
    y(i) = L_{off}, \mbox{dla } i \neq T_i
    \f}
*/
class KroneckerWaveform : public WaveformBase
{
public:

    /**
        Tworzy instancję generatora impulsu.
        Domyślnie impuls pojawia się w 25. próbce o sile jednostkowej.

        \param [in] sim Objekt symulatora odpowiedzialnego za ten przebieg.
        \param [in] initVal Poziom przebiegu w stanie biernym.
        \param [in] pulseTime Moment wystąpienia impulsu.
        \param [in] pulseValue Siła impulsu (może być ujemna).
    */
    explicit KroneckerWaveform(SimInterface::ISimulator& sim,
                            double initVal = 0, double pulseTime = 25,
                            double pulseValue = 1);

    /**
        Zwraca wartość kolejnej próbki sygnału.

        Zgodnie z definicją impulsu Kroneckera, przez większość czasu
        zwraca wartość stałą. W chwili wystąpienia impulsu wartość
        ta jest zwiększona lub zmniejszona o wartość siły impulsu.

        \return Wartość próbki.
    */
    double getNextValue();

    /**
        Ustawia moment wystąpienia impulsu.
        Wykorzystuje przeinterpretowaną zmienną określającą okres sygnału.

        \param pulseTime Czas wystąpienia impulsu.
    */
    void setPulseTime(double pulseTime) { setPeriod(pulseTime); }

    /**
        Ustawia "siłę" impulsu.
        Wykorzystuje przeinterpretowaną zmienną określającą wzmocnienie sygnału.

        \param pulseVal Siła impulsu.
    */
    void setPulseVal(double pulseVal) { setGain(pulseVal); }

    /**
        Ustawia poziom płaskiej części sygnału.
        Wykorzystuje przeinterpretowaną zmienną określającą offset sygnału.

        \param initVal Poziom sygnału.
        \exception no-throw Metoda daje gwarancję nierzucania wyjątków.
    */
    void setInitVal(double initVal) throw() { setOffset(initVal); }

    /**
        Zwraca moment wystąpienia impulsu.
        \return Moment wystąpienia impulsu.
    */
    double getPulseTime() const { return getPeriod(); }

    /**
        Zwraca siłę impulsu.
        \return Siła impulsu. Ujemna wartość oznacza impuls poniżej wartość bierną.
    */
    double getPulseVal() const { return getGain(); }

    /**
        Zwraca moment wystąpienia impulsu.
        \return Moment wystąpienia impulsu.
    */
    double getInitVal() const { return getOffset(); }

    /**
        Ustawia parametry sygnału za pomocą łańcuchów znakowych.

        Wspierane parametry:
        - action_time - moment wystąpienia impulsu.
        - init_val - wartość bierna sygnału.
        - action_val - wartość siły impulsu.

        Rozpoznawalne są również parametry z klasy bazowej WaveformBase.

        \param [in] param Parametr zmieniany.
        \param [in] value Wartość, dla podawanego parametru.
        \return True oznaczające powodzenie akcji.
        \throws std::logic_error w przypadku błędu użytkownika, składniowego lub operacji strumieniowych.
    */
    virtual bool setParameter(const std::string& param, const std::string& value) throw(std::logic_error);

    /**
        Zwraca wartość dla parametru danego łańcuchem znaków.

        Wspierane parametry są identyczne co w funkcji setParameter.

        \param [in] param Parametr odczytywany.
        \return Wartość parametru jako łańcuch znakowy.
        \throws std::logic_error w przypadku błędu użytkownika, składniowego lub operacji strumieniowych.
    */
    virtual std::string getParameter(const std::string& param) const throw(std::logic_error);

protected:
    SimFile::ConfigWriter& dumpSpecificPar(SimFile::ConfigWriter& o) const;

private:

    // Pomocnicze stałe dla interfejsu IConfigurable.
    static const std::string CONF_PULSETIME;
    static const std::string CONF_INIT;
    static const std::string CONF_PULSEVALUE;
};

}   // SimEngine namespace
}   // RafMat namespace

#endif // KRONECKERWAVEFORM_H
